import React from 'react';
import { createFragmentContainer, graphql } from 'react-relay';
import { Field, Form, Formik } from 'formik';
import * as Yup from 'yup';
import { malwareEditionOverviewFocus, malwareMutationRelationAdd, malwareMutationRelationDelete } from './MalwareEditionOverview';
import { isNone, useFormatter } from '../../../../components/i18n';
import { SubscriptionFocus } from '../../../../components/Subscription';
import OpenVocabField from '../../common/form/OpenVocabField';
import { parse } from '../../../../utils/Time';
import { adaptFieldValue } from '../../../../utils/String';
import CommitMessage from '../../common/form/CommitMessage';
import DateTimePickerField from '../../../../components/DateTimePickerField';
import { fieldSpacingContainerStyle } from '../../../../utils/field';
import { useSchemaEditionValidation } from '../../../../utils/hooks/useEntitySettings';
import useFormEditor from '../../../../utils/hooks/useFormEditor';
import AlertConfidenceForEntity from '../../../../components/AlertConfidenceForEntity';
import useApiMutation from '../../../../utils/hooks/useApiMutation';

const malwareMutationFieldPatch = graphql`
  mutation MalwareEditionDetailsFieldPatchMutation(
    $id: ID!
    $input: [EditInput]!
    $commitMessage: String
    $references: [String]
  ) {
    malwareEdit(id: $id) {
      fieldPatch(
        input: $input
        commitMessage: $commitMessage
        references: $references
      ) {
        ...MalwareEditionDetails_malware
        ...Malware_malware
      }
    }
  }
`;

const malwareEditionDetailsFocus = graphql`
  mutation MalwareEditionDetailsFocusMutation($id: ID!, $input: EditContext!) {
    malwareEdit(id: $id) {
      contextPatch(input: $input) {
        id
      }
    }
  }
`;

const MalwareEditionDetailsComponent = (props) => {
  const { malware, enableReferences, context, handleClose } = props;
  const { t_i18n } = useFormatter();
  const basicShape = {
    first_seen: Yup.date().nullable().typeError(t_i18n('The value must be a datetime (yyyy-MM-dd hh:mm (a|p)m)')),
    last_seen: Yup.date().nullable()
      .min(Yup.ref('first_seen'), "The last seen date can't be before first seen date")
      .typeError(t_i18n('The value must be a datetime (yyyy-MM-dd hh:mm (a|p)m)')),
    architecture_execution_envs: Yup.array().nullable(),
    implementation_languages: Yup.array().nullable(),
    capabilities: Yup.array().nullable(),
    references: Yup.array().required(t_i18n('This field is required')),
  };
  const malwareValidator = useSchemaEditionValidation(
    'Malware',
    basicShape,
  );
  const queries = {
    fieldPatch: malwareMutationFieldPatch,
    relationAdd: malwareMutationRelationAdd,
    relationDelete: malwareMutationRelationDelete,
    editionFocus: malwareEditionOverviewFocus,
  };
  const editor = useFormEditor(
    malware,
    enableReferences,
    queries,
    malwareValidator,
  );

  const [commitEditionDetailsFocus] = useApiMutation(malwareEditionDetailsFocus);

  const handleChangeFocus = (name) => commitEditionDetailsFocus({
    variables: {
      id: malware.id,
      input: {
        focusOn: name,
      },
    },
  });

  const onSubmit = (values, { setSubmitting }) => {
    const { message, references, ...otherValues } = values;
    const commitMessage = message ?? '';
    const commitReferences = (references ?? []).map(({ value }) => value);

    const inputValues = Object.entries({
      ...otherValues,
      first_seen: values.first_seen ? parse(values.first_seen).format() : null,
      last_seen: values.last_seen ? parse(values.last_seen).format() : null,
    }).map(([key, value]) => ({ key, value: adaptFieldValue(value) }));

    editor.fieldPatch({
      variables: {
        id: malware.id,
        input: inputValues,
        commitMessage: commitMessage && commitMessage.length > 0 ? commitMessage : null,
        references: commitReferences,
      },
      onCompleted: () => {
        setSubmitting(false);
        handleClose();
      },
    });
  };

  const handleSubmitField = (name, value) => {
    if (!enableReferences) {
      editor.fieldPatch({
        variables: {
          id: malware.id,
          input: { key: name, value: value || '' },
        },
      });
    }
  };

  const initialValues = {
    first_seen: !isNone(malware.first_seen) ? malware.first_seen : null,
    last_seen: !isNone(malware.last_seen) ? malware.last_seen : null,
    architecture_execution_envs: malware.architecture_execution_envs ?? [],
    implementation_languages: malware.implementation_languages ?? [],
    capabilities: malware.capabilities ?? [],
    references: [],
  };

  return (
    <Formik
      enableReinitialize={true}
      initialValues={initialValues}
      validationSchema={malwareValidator}
      onSubmit={onSubmit}
    >
      {({
        submitForm,
        isSubmitting,
        setFieldValue,
        values,
        isValid,
        dirty,
      }) => (
        <Form style={{ margin: '20px 0 20px 0' }}>
          <AlertConfidenceForEntity entity={malware} />
          <Field
            component={DateTimePickerField}
            name="first_seen"
            onFocus={handleChangeFocus}
            onSubmit={handleSubmitField}
            textFieldProps={{
              label: t_i18n('First seen'),
              variant: 'standard',
              fullWidth: true,
              helperText: (
                <SubscriptionFocus context={context} fieldName="first_seen"/>
              ),
            }}
          />
          <Field
            component={DateTimePickerField}
            name="last_seen"
            onFocus={handleChangeFocus}
            onSubmit={handleSubmitField}
            textFieldProps={{
              label: t_i18n('Last seen'),
              variant: 'standard',
              fullWidth: true,
              style: { marginTop: 20 },
              helperText: (
                <SubscriptionFocus context={context} fieldName="last_seen"/>
              ),
            }}
          />
          <OpenVocabField
            label={t_i18n('Architecture execution env.')}
            type="processor-architecture-ov"
            name="architecture_execution_envs"
            onFocus={handleChangeFocus}
            onSubmit={handleSubmitField}
            onChange={(name, value) => setFieldValue(name, value)}
            containerStyle={fieldSpacingContainerStyle}
            variant="edit"
            multiple={true}
            editContext={context}
          />
          <OpenVocabField
            label={t_i18n('Implementation languages')}
            type="implementation-language-ov"
            name="implementation_languages"
            onFocus={handleChangeFocus}
            onSubmit={handleSubmitField}
            onChange={(name, value) => setFieldValue(name, value)}
            containerStyle={fieldSpacingContainerStyle}
            variant="edit"
            multiple={true}
            editContext={context}
          />
          <OpenVocabField
            label={t_i18n('Capabilities')}
            type="malware-capabilities-ov"
            name="capabilities"
            onFocus={handleChangeFocus}
            onSubmit={handleSubmitField}
            onChange={(name, value) => setFieldValue(name, value)}
            containerStyle={fieldSpacingContainerStyle}
            variant="edit"
            multiple={true}
            editContext={context}
          />
          {enableReferences && (
          <CommitMessage
            submitForm={submitForm}
            disabled={isSubmitting || !isValid || !dirty}
            setFieldValue={setFieldValue}
            open={false}
            values={values.references}
            id={malware.id}
          />
          )}
        </Form>
      )}
    </Formik>
  );
};

export default createFragmentContainer(MalwareEditionDetailsComponent, {
  malware: graphql`
      fragment MalwareEditionDetails_malware on Malware {
        id
        first_seen
        last_seen
        architecture_execution_envs
        implementation_languages
        capabilities
        confidence
        entity_type
      }
    `,
});
